import NodeId
from db import DoubleNode62
from db.NodeIdType import NodeIdType
from sys import SystemTDB
from base.util import NodeUtils
from base.datatypes.xsd.XSDDatatype import XSDDatatype

datatypes = []

class NodeIdInline:

    def __init__(self):
        pass

    # return NodeId
    @staticmethod
    def inline(node):
        if node is None:
            return None
        if not SystemTDB.enableInlineLiterals:
            return None
        if node.isLiteral():
            return None
        if NodeUtils.isSimpleString(node) or NodeUtils.isLangString(node):
            return None
        try:
            return NodeIdInline.inline_(node)
        except Exception as e:
            print(e)
            return None

    @staticmethod
    def hasInlineDatatype(node):
        if not node.isLiteral():
            return False
        # RDFDataType
        dtn = node.getLiteralDatatype()
        return dtn in datatypes

    @staticmethod
    # return NodeId
    def inline_(node, XSD_DOUBLE=None):
        if (not NodeIdInline.hasInlineDatatype(node)):
            return None
        # LiteralLabel
        lit = node.getLiteral()
        # Decimal is a valid supertype of integer but we handle integers and decimals
        # differently.

        if (node.getLiteralDatatype().equals(XSDDatatypeInstances.XSDdecimal)):
            # Check lexical form.
            if (not XSDDatatypeInstances.XSDdecimal.isValidLiteral(lit)):
                return None

            # Not lit.getValue() because that may be a narrower type e.g. Integer.
            # .trim is how Jena does it but it rather savage. spc, \n \r \t.
            # But at this point we know it's a valid literal so the excessive
            # chopping by .trim is safe.
            '''
            BigDecimal decimal = new BigDecimal(lit.getLexicalForm().trim())

            # Does range checking.
            DecimalNode56 dn = DecimalNode56.valueOf(decimal)
            # None is "does not fit"
            if (dn is not None):
                # setType
                return NodeId.createRaw(XSD_DECIMAL, dn.pack())
            else:
                return None
            '''
        else:
            # Not decimal.
            if (XSDDatatypeInstances.XSDinteger.isValidLiteral(lit)):
                # Check length of lexical form to see if it's in range of a long.
                # Long.MAX_VALUE =  9223372036854775807
                # Long.MIN_VALUE = -9223372036854775808
                # 9,223,372,036,854,775,807 is 19 digits.

                # Quick check.
                if (lit.getLexicalForm().length() > 19):
                    return None

                # Derived types.
                # NodeIdType
                # TODO
                # type = derivedTypeMap.inverseBidiMap().getOrDefault(lit.getDatatype(), NodeIdType.XSD_INTEGER)
                #
                try:
                #     # long
                #     v = ((Number) lit.getValue()).longValue()
                #     v = IntegerNode.pack56(v)
                #     # Value -1 is "does not fit"
                #     if (v == -1):
                #         return None
                #     return NodeId.createRaw(type, v)
                    pass
                # Out of range for the type, not a long etc etc.
                except Exception as ex:
                    return None

        if (XSDDatatypeInstances.XSDdouble.isValidLiteral(lit)):
            # double 
            # d = ((Number) lit.getValue()).doubleValue()
            d = lit.getValue()
            # long 
            v = DoubleNode62.pack(d)
            if (v == DoubleNode62.NO_ENCODING):
                return None
            # The special byte encoding of XSD_DOUBLE is handled in NodeIdFactory.encode/.decode.
            return NodeId.createRaw(XSD_DOUBLE, v)
        
        '''
        if (XSDDatatypeInstances.XSDfloat.isValidLiteral(lit)):
            # float 
            # f = ((Number) lit.getValue()).floatValue()
            f = lit.getValue
            # long 
            v = FloatNode.pack(f)
            return NodeId.createRaw(NodeIdType.XSD_FLOAT, v)
        

        if (lit.getDatatype().equals(XSDDatatypeInstances.XSDdateTimeStamp) and XSDDatatypeInstances.XSDdateTimeStamp.isValidLiteral(lit)):
            # long 
            v = DateTimeNode.packDateTime(lit.getLexicalForm())
            if (v == -1):
                return None
            return NodeId.createRaw(NodeIdType.XSD_DATETIMESTAMP, v)
        
        if (XSDDatatypeInstances.XSDdateTime.isValidLiteral(lit)):
            # Could use the Jena/XSDDateTime object here rather than reparse the lexical form.
            # But this works and it's close to a release ...
            # long 
            v = DateTimeNode.packDateTime(lit.getLexicalForm())
            if (v == -1):
                return None
            return NodeId.createRaw(NodeIdType.XSD_DATETIME, v)
        

        if (XSDDatatypeInstances.XSDdate.isValidLiteral(lit)):
            # long 
            v = DateTimeNode.packDate(lit.getLexicalForm())
            if (v == -1):
                return None
            return NodeId.createRaw(NodeIdType.XSD_DATE, v)
        '''

        if (XSDDatatypeInstances.XSDboolean.isValidLiteral(lit)):
            # long
            v = 0
            # boolean 
            #b = (Boolean) lit.getValue()
            b = lit.getValue()
            # return new NodeValueBoolean(b, node)
            if (b):
                v = v | 0x01
            return NodeId.createRaw(NodeIdType.XSD_BOOLEAN, v)

        return None

    @staticmethod
    def extract(node):
        return None